home *** CD-ROM | disk | FTP | other *** search
/ MIDICraft's MIDINET CD-ROM / MIDICraft's MIDINET CD-ROM.iso / DOSUTILS / KORGI3 / MIDIPLAY.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-02  |  14.0 KB  |  719 lines

  1. static char* version = "midiplay v1.0 by Günter Nagler (" __DATE__ ")";
  2.  
  3. #include "midiio.hpp"
  4. #include <stdlib.h>
  5. #include <ctype.h>
  6. #include <string.h>
  7. #include <dos.h>
  8. #include "sb.hpp"
  9. #include "mpu.hpp"
  10. #include "sndcard.hpp"
  11. #include <conio.h>
  12. #include "timer.hpp"
  13.  
  14. #define MILLISEC   //timer always milliseconds
  15.  
  16. class MidiPlay;
  17.  
  18. Soundcard* card = 0;
  19. MidiPlay* midi = 0;
  20. int lyrics = 1;
  21. int gm = 0;
  22. long seekpos = 0;
  23. unsigned char vol[16];
  24. char playchannel[16];
  25.  
  26. #define TEMPNAME "xxxxxxxx.xxx"
  27.  
  28. char tempname[128] = TEMPNAME;
  29.  
  30. Timer watch;
  31.  
  32. class MidiPlay : public MidiRead
  33. {
  34. public:
  35.   MidiPlay(char* name);
  36.  
  37.   virtual void head(unsigned version, unsigned tracks, unsigned clicksperquarter);
  38.   virtual void track(int trackno, long length, int channel);
  39.   virtual void endtrack(int trackno);
  40.  
  41.   virtual void seqnumber(unsigned int seqno);
  42.   virtual void text(int what, int len, char* whattext, unsigned char* txt);
  43.   virtual void meta(int what, int len, unsigned char* data);
  44.   virtual void end();
  45.   virtual void prefixchannel(unsigned char channel);
  46.   virtual void prefixport(unsigned char port);
  47.   virtual void smpteofs(int hour, int min, int sec, int frame, int fracframe);
  48.   virtual void tact(int nom, int denom, int clicksperbeat, int notes32perbeat);
  49.   virtual void tempo(unsigned long ticks);
  50.   virtual void key(int signature, int isminor);
  51.  
  52.   virtual void program(int prg, int channel);
  53.   virtual void control(int channel, int what, int value);
  54.   virtual void noteon(int channel, int note, int vel);
  55.   virtual void noteoff(int channel, int note, int vel);
  56.   virtual void time(unsigned long ticks);
  57.   virtual void pitchbend(int channel, int val);
  58.   virtual void polyaftertouch(int channel, int note, int val);
  59.   virtual void aftertouch(int channel, int val);
  60.   virtual void songpos(unsigned pos);
  61.   virtual void songselect(unsigned char song);
  62.   virtual void tunerequest();
  63.   virtual void timingclock();
  64.   virtual void start();
  65.   virtual void cont();
  66.   virtual void stop();
  67.   virtual void activesense();
  68.   virtual void sysex(int syslen, unsigned char* sysdata);
  69.   virtual void endmidi();
  70.   virtual void error(const char* msg);
  71.  
  72.   virtual void percent(int perc);
  73.  
  74.   long errorcnt_;
  75.  
  76.   void reset();
  77. private:
  78.   unsigned tactunits_;
  79.   unsigned quarterunits_;
  80.   unsigned long curtime_;
  81.  
  82.   int nl_;
  83.   int endmark_;  // each track should contain FF 2F 00 as last command
  84.  
  85.   unsigned long microsecperunit;
  86.  
  87.   unsigned char noteplaying_[16][128];
  88.   int karaoke_;
  89. };
  90.  
  91. static int aborted = 0;
  92.  
  93. int abortkey()
  94. {
  95.   if (aborted)
  96.     return 1;
  97.   if (kbhit() && getch() == 27)
  98.   {
  99.     aborted = 1;
  100.     if (midi)
  101.       midi->reset();
  102.   }
  103.   return aborted;
  104. }
  105.  
  106. void watchdelay(int millisec)
  107. {
  108.   if (millisec <= 0)
  109.     return;
  110.   unsigned long endtime = watch.curtime_ + millisec;
  111.   while (watch.curtime_ < endtime)
  112.     ;
  113. }
  114.  
  115. void setvol(int channel, int val)
  116. {
  117.   if (!card)
  118.     return;
  119.    unsigned char data[3];
  120.  
  121.    data[0] = 0xB0 + channel;
  122.    data[1] = ctrl_volume;
  123.    data[2] = val;
  124.    card->play(data, 3);
  125.    watchdelay(25);
  126. //   printf("setvol[%d] to %d\n", channel, val);
  127. }
  128.  
  129. MidiPlay::MidiPlay(char* name) : MidiRead(name)
  130. {
  131.   nl_ = 1;
  132.   errorcnt_ = 0;
  133.   microsecperunit = 0;
  134.   karaoke_ = 0;
  135. }
  136.  
  137. void MidiPlay::head(unsigned version, unsigned tracks, unsigned clicksperquarter)
  138. {
  139.   memset(noteplaying_, 0, sizeof(noteplaying_));
  140.   quarterunits_ = clicksperquarter;
  141.   microsecperunit = 500000L / clicksperquarter;
  142.  
  143.   if (tracks_ == 0)
  144.     error("no track found");
  145.  
  146.   if (version != 0)
  147.   {
  148.     fprintf(stderr, "format %d currently not supported\n", version);
  149.     exit(1);
  150.   }
  151. }
  152.  
  153. void MidiPlay::track(int trackno, long length, int channel)
  154. {
  155.   endmark_ = 0;
  156.   curtime_ = 0;
  157. }
  158.  
  159. void MidiPlay::endtrack(int trackno)
  160. {
  161.   if (!endmark_)
  162.     printf(" // Warning: end of track meta event missing\n");
  163.  
  164.   if (!nl_)
  165.   {
  166.     nl_ = 1;
  167.     printf("\n");
  168.   }
  169. }
  170.  
  171. void printchar(int c)
  172. {
  173.   if (c < 0)
  174.     return;
  175.   if (c == '\\')
  176.     printf("\\\\");
  177.   else if (c == '"')
  178.     printf("\\\"");
  179.   else if (c != 0 && (isprint(c) || strchr("äöüÄÖÜß", c) != 0))
  180.     putchar(c);
  181.   else
  182.     printf("\\x%02x", c);
  183. }
  184.  
  185. void MidiPlay::seqnumber(unsigned int seqno)
  186. {
  187. }
  188.  
  189. void MidiPlay::text(int what, int len, char* whattext, unsigned char* txt)
  190. {
  191.   if (!txt)
  192.     return;
  193.   if (aborted)
  194.     return;
  195.   if (getcurtime() < seekpos)
  196.     return;
  197.   if (what == meta_lyric || what == meta_text)
  198.   {
  199.   char* bs;
  200.  
  201.     while ((bs = (char*)memchr(txt, '\\', len)) != 0)
  202.       *bs = '\n';
  203.     while ((bs = (char*)memchr(txt, '/', len)) != 0)
  204.       *bs = '\n';
  205.     if (*txt == '@')
  206.     {
  207.       karaoke_ = 1;
  208.       txt++; len--;
  209.       switch(*txt)
  210.       {
  211.       case 'K': printf("\nKind: "); break;
  212.       case 'V': printf("\nVersion: "); break;
  213.       case 'I': printf("\nInformation: "); break;
  214.       case 'T': printf("\nTitle: "); break;
  215.       case 'L': printf("\nLanguage: "); break;
  216.       default:  printf("\n@%c: ", *txt); break;
  217.       }
  218.       if (*txt)
  219.       {
  220.     txt++;
  221.     len--;
  222.       }
  223.     }
  224.     if (txt[len-1] == '\r')
  225.       txt[len-1] = '\n';
  226.     nl_ = txt[len-1] == '\n';
  227.     printf("%.*s", len, txt);
  228.     if (!karaoke_)
  229.       printf("\n");
  230.   }
  231. }
  232.  
  233. void MidiPlay::meta(int what, int len, unsigned char* data)
  234. {
  235. }
  236.  
  237. void MidiPlay::end()
  238. {
  239.   endmark_ = 1;
  240. }
  241.  
  242. void MidiPlay::prefixchannel(unsigned char channel)
  243. {
  244. }
  245.  
  246. void MidiPlay::prefixport(unsigned char port)
  247. {
  248. }
  249.  
  250.  
  251. void MidiPlay::smpteofs(int hour, int min, int sec, int frame, int fracframe)
  252. {
  253. }
  254.  
  255. void MidiPlay::tact(int nom, int denom, int clicksperbeat, int notes32perbeat)
  256. {
  257. }
  258.  
  259. void MidiPlay::tempo(unsigned long microsecperbeat)
  260. {
  261.   microsecperunit = microsecperbeat / quarterunits_;
  262. #ifndef MILLISEC
  263.   watch.setspeed(unsigned(microsecperbeat / (quarterunits_ * 1000L)), 1);
  264. #endif
  265. }
  266.  
  267. void MidiPlay::key(int signature, int isminor)
  268. {
  269. }
  270.  
  271. void MidiPlay::time(unsigned long units)
  272. {
  273.   if (units == 0)
  274.     return;
  275.   long tim = getcurtime();
  276.   if (tim + units <= seekpos)  // quick forward
  277.     return;
  278.   if (tim <= seekpos && seekpos > 0)
  279.   {
  280.     if (seekpos > 0)
  281.       fprintf(stderr, "\rplaying...\n");
  282.     units = tim + units - seekpos;
  283.     for (int i = 0; i < 16; i++)
  284.       setvol(i, vol[i]);
  285.   }
  286. #ifndef MILLISEC
  287.   int maxunits;
  288.   do
  289.   {
  290.     if (abortkey())
  291.       return;
  292.     maxunits = 50;
  293.     if (units < maxunits)
  294.        maxunits = (int)units;
  295.     watchdelay(maxunits);
  296.     units -= maxunits;
  297.   } while (maxunits > 0);
  298. #endif
  299.  
  300. #ifdef MILLISEC
  301.   unsigned millisec = (unsigned) (units * microsecperunit / 1000);
  302.  
  303.   do
  304.   {
  305.     if (abortkey())
  306.       return;
  307.     if (millisec >= 100)
  308.     {
  309.        watchdelay(100);
  310.        millisec -= 100;
  311.     }
  312.     else
  313.     {
  314.       watchdelay(millisec);
  315.       break;
  316.     }
  317.   } while (millisec > 0);
  318. #endif
  319. }
  320.  
  321. void MidiPlay::program(int channel, int prg)
  322. {
  323. unsigned char s[2];
  324.  
  325.   if (aborted)
  326.     return;
  327.  
  328.   if (!playchannel[channel])
  329.     return;
  330.   s[0] = 0xc0 + channel;
  331.   s[1] = prg;
  332.   card->play(s, 2);
  333. }
  334.  
  335. void MidiPlay::control(int channel, int what, int value)
  336. {
  337. unsigned char s[3];
  338.  
  339.   if (aborted)
  340.     return;
  341.  
  342.   if (!playchannel[channel])
  343.     return;
  344.   if (what == ctrl_volume)
  345.   {
  346.     if (getcurtime() < seekpos)
  347.     {
  348.       vol[channel] = value;
  349.       return;
  350.     }
  351.   }
  352.  
  353.   s[0] = 0xb0 + channel;
  354.   s[1] = what;
  355.   s[2] = value;
  356.   card->play(s, 3);
  357. }
  358.  
  359. void MidiPlay::noteon(int channel, int note, int vel)
  360. {
  361. unsigned char s[3];
  362.  
  363.   if (aborted)
  364.     return;
  365.  
  366.   if (!playchannel[channel])
  367.     return;
  368.   s[0] = 0x90 + channel;
  369.   s[1] = note;
  370.   s[2] = vel;
  371.   card->play(s, 3);
  372.   noteplaying_[channel][note] = 1;
  373. }
  374.  
  375. void MidiPlay::noteoff(int channel, int note, int vel)
  376. {
  377. unsigned char s[3];
  378.  
  379.   if (aborted)
  380.     return;
  381.   if (!playchannel[channel])
  382.     return;
  383.   s[0] = 0x80 + channel;
  384.   s[1] = note;
  385.   s[2] = vel;
  386.   card->play(s, 3);
  387.   watchdelay(5);
  388.   noteplaying_[channel][note] = 0;
  389. }
  390.  
  391. void MidiPlay::pitchbend(int channel, int val)
  392. {
  393. unsigned char s[3];
  394.  
  395.   if (aborted)
  396.     return;
  397.  
  398.   if (!playchannel[channel])
  399.     return;
  400.   s[0] = 0xE0 + channel;
  401.   s[1] = val & 0x7f;
  402.   s[2] = (val >> 7) & 0x7f;
  403.   card->play(s, 3);
  404. }
  405.  
  406. void MidiPlay::polyaftertouch(int channel, int note, int val)
  407. {
  408. unsigned char s[3];
  409.  
  410.   if (aborted)
  411.     return;
  412.  
  413.   if (!playchannel[channel])
  414.     return;
  415.   s[0] = 0xa0 + channel;
  416.   s[1] = note;
  417.   s[2] = val;
  418.   card->play(s, 3);
  419. }
  420.  
  421. void MidiPlay::aftertouch(int channel, int val)
  422. {
  423. unsigned char s[2];
  424.  
  425.   if (aborted)
  426.     return;
  427.  
  428.   if (!playchannel[channel])
  429.     return;
  430.   s[0] = 0xd0 + channel;
  431.   s[1] = val;
  432.   card->play(s, 2);
  433. }
  434.  
  435. void MidiPlay::songpos(unsigned pos)
  436. {
  437. }
  438.  
  439. void MidiPlay::songselect(unsigned char song)
  440. {
  441. }
  442.  
  443. void MidiPlay::tunerequest()
  444. {
  445. }
  446.  
  447. void MidiPlay::timingclock()
  448. {
  449. }
  450.  
  451. void MidiPlay::start()
  452. {
  453. }
  454.  
  455. void MidiPlay::cont()
  456. {
  457. }
  458.  
  459. void MidiPlay::stop()
  460. {
  461. }
  462.  
  463. void MidiPlay::activesense()
  464. {
  465. }
  466.  
  467. void MidiPlay::sysex(int syslen, unsigned char* sysdata)
  468. {
  469. unsigned char c;
  470.  
  471.   c = 0xf0;
  472.   card->play(&c, 1);
  473.   card->play(sysdata, syslen);
  474. }
  475.  
  476. void MidiPlay::endmidi()
  477. {
  478. }
  479.  
  480. void MidiPlay::percent(int perc)
  481. {
  482. }
  483.  
  484. void MidiPlay::error(const char* msg)
  485. {
  486.   printf("// error: %s\n", msg);
  487.   errorcnt_++;
  488. }
  489.  
  490. void usage()
  491. {
  492.   fprintf(stderr, "usage: midiplay [-gm] [-nolyric] [-seek #] [-c #] file.mid\n");
  493.   exit(1);
  494. }
  495.  
  496. void MidiPlay::reset()
  497. {
  498. unsigned char c[3];
  499.  
  500.   for (int n = 0; n < 127; n++)
  501.   {
  502.     for (int i = 0; i < 16; i++)
  503.     if (noteplaying_[i][n])
  504.     {
  505.       c[0] = 0x80+i;
  506.       c[1] = n;
  507.       c[2] = 0;
  508.       card->play(c, 3);
  509.       noteplaying_[i][n] = 0;
  510.     }
  511.   }
  512. }
  513.  
  514. int midiplayonetrack(char* filename, int temp = 0)
  515. {
  516.   midi = new MidiPlay(filename);
  517.   if (!midi)
  518.   {
  519.     fprintf(stderr, "not enough memory\n");
  520.     return 1;
  521.   }
  522.   if (!midi->getf())
  523.   {
  524.     if (!temp)
  525.       perror(filename);
  526.     return 1;
  527.   }
  528.   card = detect_soundcard();
  529.   if (!card)
  530.   {
  531.     fprintf(stderr, "Could not detect soundcard\n");
  532.     return 1;
  533.   }
  534.  
  535.   if (gm)
  536.   {
  537.   unsigned char sysex_gmreset[] = { 0xF0, 0x7E, 0x7F, 0x09, 0x01, 0xF7 };
  538.  
  539.     card->play(sysex_gmreset, sizeof(sysex_gmreset));
  540.   }
  541.  
  542.   if (seekpos > 0)
  543.     fprintf(stderr, "seeking...\n");
  544.   for (int i = 0; i < 16; i++)
  545.   {
  546.     vol[i] = 100;
  547.     if (seekpos > 0)
  548.       setvol(i, 0);
  549.   }
  550.  
  551.   watch.setspeed(SPEED_MILLISEC);
  552.   unsigned long start = watch.curtime_;
  553.   for (int t = 0; t < 1000; t++)
  554.   if (watch.curtime_ != start)
  555.     break;
  556.   else if (abortkey())
  557.     break;
  558.   if (t >= 1000)
  559.   {
  560.     fprintf(stderr, "timer not working\n");
  561.     aborted = 1;
  562.   }
  563.  
  564.   midi->options_ = OPTION_NOCONTROLS | OPTION_NOSYSEVENTS;
  565.   int ret = midi->run();
  566.   midi->reset();
  567.   if (aborted)
  568.     fprintf(stderr, "aborted ...\n");
  569.   delete card;
  570.   if (!ret)
  571.   {
  572.     printf("%s: midi error at 0x%04lx\n", filename, midi->getpos());
  573.     return 1;
  574.   }
  575.   return 0;
  576. }
  577.  
  578. typedef struct
  579. {
  580.   char id[4];
  581.   char size[4];  // 6
  582.   unsigned char fmt[2]; // 0, 1, 2
  583.   unsigned char tracks[2];
  584. } MIDIHEADER;
  585.  
  586. int midiplay(char* filename)
  587. {
  588.   fprintf(stderr, "%s\n", filename);
  589.   FILE* f = fopen(filename, "rb");
  590.   if (!f)
  591.   {
  592.     perror(filename);
  593.     return 1;
  594.   }
  595.   rewind(f);
  596.   MIDIHEADER header;
  597.   int ret = fread(&header, sizeof(header), 1, f);
  598.   fclose(f);
  599.   long size = 0;
  600.   size = (size << 8) + header.size[0];
  601.   size = (size << 8) + header.size[1];
  602.   size = (size << 8) + header.size[2];
  603.   size = (size << 8) + header.size[3];
  604.   int format = 0;
  605.   format = (format << 8) + header.fmt[0];
  606.   format = (format << 8) + header.fmt[1];
  607.   int tracks = 0;
  608.   tracks = (tracks << 8) + header.tracks[0];
  609.   tracks = (tracks << 8) + header.tracks[1];
  610.   if (ret != 1 || strncmp(header.id, "MThd", 4) != 0 ||
  611.      size != 6 || format < 0 || format > 2)
  612.   {
  613.     fprintf(stderr, "%s: not a standard midi file\n", filename);
  614.     return 1;
  615.   }
  616.   if (format == 2)
  617.   {
  618.     fprintf(stderr, "%s: cannot play format 2. Use midi2to0 to convert to format 0.\n", filename);
  619.     return 1;
  620.   }
  621.   if (tracks == 0)
  622.   {
  623.     fprintf(stderr, "%s: contains no track\n", filename);
  624.     return 1;
  625.   }
  626.   if (format == 1 || tracks != 1)
  627.   {
  628.   char cmd[128];
  629.  
  630.     sprintf(cmd, "midi1to0 -q %s %s", filename, tempname);
  631.     int ret = system(cmd);
  632.     if (ret == 0)
  633.       midiplayonetrack(tempname, 1);
  634.     unlink(tempname);
  635.     return ret;
  636.   }
  637.   else
  638.     return midiplayonetrack(filename);
  639. }
  640.  
  641. int main(int argc, char**argv)
  642. {
  643.   argc--; argv++;
  644.   for (int i = 0; i < 16; i++)
  645.     playchannel[i] = 0;
  646.  
  647.   while (argc > 0 && **argv == '-')
  648.   {
  649.     if (strncmp(*argv, "-version", 2) == 0)
  650.     {
  651.       fprintf(stderr, "%s\n", version);
  652.       argc--; argv++;
  653.       if (argc == 0)
  654.     return 0;
  655.       continue;
  656.     }
  657.     if (argc > 0 && strncmp(*argv, "-nolyric", 2) == 0)
  658.     {
  659.       lyrics = 0;
  660.       argc--; argv++;
  661.       continue;
  662.     }
  663.     if (argc > 0 && strncmp(*argv, "-seek", 2) == 0)
  664.     {
  665.       argc--; argv++;
  666.       if (argc == 0)
  667.     fprintf(stderr, "option -seek needs a position\n");
  668.       else
  669.       {
  670.       char* end;
  671.  
  672.     seekpos = strtoul(*argv, &end, 0);
  673.     argc--; argv++;
  674.       }
  675.       continue;
  676.     }
  677.     if (argc > 0 && strncmp(*argv, "-c", 2) == 0)
  678.     {
  679.       argc--; argv++;
  680.       if (argc == 0)
  681.     fprintf(stderr, "option -c needs a channel number (1-16)\n");
  682.       else
  683.       {
  684.       char* end;
  685.       long ch;
  686.  
  687.     ch = strtoul(*argv, &end, 0);
  688.     if (ch <= 0 || ch > 16)
  689.       fprintf(stderr, "invalid channel number %s (should be 1-16)\n", *argv);
  690.     else
  691.       playchannel[(int)ch-1] = 1;
  692.     argc--; argv++;
  693.       }
  694.       continue;
  695.     }
  696.     if (argc > 0 && strncmp(*argv, "-gm", 2) == 0)
  697.     {
  698.       gm = 1;
  699.       argc--; argv++;
  700.       continue;
  701.     }
  702.     fprintf(stderr, "invalid option %s\n", *argv);
  703.     argc--; argv++;
  704.     usage();
  705.   }
  706.   if (argc == 0)
  707.     usage();
  708.  
  709.   for (i = 0; i< 16; i++)
  710.   if (playchannel[i])
  711.     break;
  712.   if (i >= 16)
  713.   for (i = 0; i< 16; i++)  // default: play all channels
  714.     playchannel[i] = 1;
  715.  
  716.   return midiplay(*argv);
  717. }
  718.  
  719.